~golfish/netbook-remix-launcher/desktop

« back to all changes in this revision

Viewing changes to src/launcher-startup.c

  • Committer: Neil J. Patel
  • Date: 2008-04-16 11:31:15 UTC
  • Revision ID: njpatel@gmail.com-20080416113115-ztljg0qms79anijd
* Inital import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2007 Intel
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or
 
5
 * modify it under the terms of the GNU General Public
 
6
 * License as published by the Free Software Foundation; either
 
7
 * version 2 of the License, or (at your option) any later version.
 
8
 *
 
9
 * This library is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
 * Lesser General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public
 
15
 * License along with this library; if not, write to the
 
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
17
 * Boston, MA 02111-1307, USA.
 
18
 *
 
19
 * Authored by Neil Jagdish Patel <njp@o-hand.com>
 
20
 *
 
21
 */
 
22
 
 
23
#include <glib.h>
 
24
#include <gdk/gdkx.h>
 
25
#include <gdk/gdk.h>
 
26
 
 
27
#include <stdio.h>
 
28
#include <string.h>
 
29
 
 
30
#include <X11/Xlib.h>
 
31
#include <X11/Xutil.h>
 
32
 
 
33
#define SN_API_NOT_YET_FROZEN 1
 
34
#include <libsn/sn.h>
 
35
 
 
36
#include "launcher-startup.h"
 
37
#include "launcher-menu.h"
 
38
#include "launcher-util.h"
 
39
 
 
40
G_DEFINE_TYPE (LauncherStartup, launcher_startup, G_TYPE_OBJECT)
 
41
 
 
42
#define LAUNCHER_STARTUP_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE(obj, \
 
43
        LAUNCHER_TYPE_STARTUP, LauncherStartupPrivate))
 
44
 
 
45
#define TIMEOUT 3000 /* Miliseconds */
 
46
#define SN_TIMEOUT 10000
 
47
 
 
48
struct _LauncherStartupPrivate
 
49
{
 
50
  GdkWindow *root_window;
 
51
  SnDisplay *sn_display;
 
52
  Display *xdisplay;
 
53
 
 
54
  ClutterActor *active;
 
55
 
 
56
  gchar **argv;
 
57
  guint tag;
 
58
};
 
59
 
 
60
/*
 
61
 * Public functions
 
62
 */
 
63
 
 
64
/*
 
65
 * Load settings from the desktop file, this is important for the launch
 
66
 * sequence.
 
67
 */
 
68
#if 0
 
69
static void
 
70
load_settings (LauncherItem  *item, 
 
71
               gboolean      *sn_enable,
 
72
               gboolean      *single_instance,
 
73
               gchar         ***argv)
 
74
{
 
75
  LauncherMenuApplication *app;
 
76
  GKeyFile *key_file;
 
77
  GError *error = NULL;
 
78
  const gchar *filename;
 
79
  const gchar *exec;
 
80
 
 
81
  g_return_if_fail (LAUNCHER_IS_ITEM (item));
 
82
 
 
83
  app = NULL;//launcher_item_get_application (item);
 
84
 
 
85
  /* Get the exec string */
 
86
  exec = launcher_menu_application_get_exec (app);
 
87
 
 
88
  if (exec == NULL)
 
89
    return;
 
90
 
 
91
  /* Create an argv from the string */
 
92
  *argv = launcher_util_exec_to_argv (exec);
 
93
 
 
94
 
 
95
  key_file = g_key_file_new ();
 
96
  filename = launcher_menu_application_get_desktop_filename (app);
 
97
 
 
98
  if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &error))
 
99
  {
 
100
    g_key_file_free (key_file);
 
101
    g_warning ("Unable to load Desktop File values: %s", error->message);
 
102
    g_error_free (error);
 
103
    return;
 
104
  }
 
105
 
 
106
  *single_instance = g_key_file_get_boolean (key_file, "Desktop Entry", 
 
107
                                                  "SingleInstance", NULL);
 
108
  *sn_enable = g_key_file_get_boolean (key_file, "Desktop Entry", 
 
109
                                            "StartupNotify", NULL);
 
110
 
 
111
  g_key_file_free (key_file);
 
112
}
 
113
#endif
 
114
static void
 
115
load_app_settings (LauncherMenuApplication   *app, 
 
116
                   gboolean                  *sn_enable,
 
117
                   gboolean                  *single_instance,
 
118
                   gchar                   ***argv)
 
119
{
 
120
  GKeyFile *key_file;
 
121
  GError *error = NULL;
 
122
  const gchar *filename;
 
123
  const gchar *exec;
 
124
 
 
125
  g_return_if_fail (app);
 
126
 
 
127
  /* Get the exec string */
 
128
  exec = launcher_menu_application_get_exec (app);
 
129
 
 
130
  if (exec == NULL)
 
131
    return;
 
132
 
 
133
  /* Create an argv from the string */
 
134
  *argv = launcher_util_exec_to_argv (exec);
 
135
 
 
136
 
 
137
  key_file = g_key_file_new ();
 
138
  filename = launcher_menu_application_get_desktop_filename (app);
 
139
 
 
140
  if (!g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, &error))
 
141
  {
 
142
    g_key_file_free (key_file);
 
143
    g_warning ("Unable to load Desktop File values: %s", error->message);
 
144
    g_error_free (error);
 
145
    return;
 
146
  }
 
147
 
 
148
  *single_instance = g_key_file_get_boolean (key_file, "Desktop Entry", 
 
149
                                                  "SingleInstance", NULL);
 
150
  *sn_enable = g_key_file_get_boolean (key_file, "Desktop Entry", 
 
151
                                            "StartupNotify", NULL);
 
152
 
 
153
  g_key_file_free (key_file);
 
154
}
 
155
 
 
156
 
 
157
static void
 
158
child_setup (gpointer user_data)
 
159
{
 
160
  if (user_data)
 
161
    sn_launcher_context_setup_child_process (user_data);
 
162
}
 
163
 
 
164
static gboolean
 
165
sn_timeout (LauncherStartup *startup)
 
166
{
 
167
  LauncherStartupPrivate *priv;
 
168
 
 
169
  g_return_val_if_fail (LAUNCHER_IS_STARTUP (startup), FALSE);
 
170
  priv = startup->priv;
 
171
 
 
172
  /*
 
173
  if (!LAUNCHER_IS_ITEM (priv->active))
 
174
    return FALSE;*/
 
175
 
 
176
  //launcher_item_launch_completed (priv->active);
 
177
  g_strfreev (priv->argv);
 
178
  priv->argv = NULL;
 
179
  priv->active = NULL;
 
180
  
 
181
  return FALSE;
 
182
}
 
183
 
 
184
#if 0
 
185
 
 
186
gboolean
 
187
launcher_startup_launch_item (LauncherStartup *startup, LauncherItem *item)
 
188
{
 
189
  LauncherStartupPrivate *priv;
 
190
  LauncherMenuApplication *app;
 
191
  GError *error = NULL;
 
192
  SnLauncherContext *context = NULL;
 
193
  gboolean sn_enable = FALSE;;
 
194
  gboolean single_instance = FALSE;
 
195
  gint pid;
 
196
 
 
197
  g_return_val_if_fail (LAUNCHER_IS_STARTUP (startup), FALSE);
 
198
  priv = startup->priv;
 
199
  
 
200
  priv->active = item;
 
201
  app = NULL;//launcher_item_get_application (item);
 
202
 
 
203
  /* Load the important settings from the desktop file if not already done */
 
204
  load_settings (item, &sn_enable, &single_instance, &priv->argv);
 
205
 
 
206
  if (sn_enable)
 
207
  {
 
208
    SnDisplay *sn_dpy;
 
209
    Display *display;
 
210
    int screen;
 
211
 
 
212
    display = priv->xdisplay;
 
213
    sn_dpy = priv->sn_display;
 
214
 
 
215
    screen = gdk_screen_get_number (gdk_screen_get_default ());
 
216
    
 
217
    context = sn_launcher_context_new (sn_dpy, screen);
 
218
 
 
219
    sn_launcher_context_set_name (context,
 
220
                                launcher_menu_application_get_name (app));
 
221
    sn_launcher_context_set_binary_name (context, priv->argv[0]);
 
222
 
 
223
    sn_launcher_context_initiate (context,
 
224
                                  g_get_prgname () ?: "unknown",
 
225
                                  priv->argv[0],
 
226
                                  CLUTTER_CURRENT_TIME);
 
227
  }
 
228
 
 
229
  /* Execute the program */
 
230
  if (!gdk_spawn_on_screen (gdk_screen_get_default (),
 
231
                            NULL, priv->argv, NULL,
 
232
                            G_SPAWN_SEARCH_PATH,
 
233
                            child_setup,
 
234
                            context,
 
235
                            &pid,
 
236
                            &error))
 
237
  {
 
238
    g_warning ("Cannot launch %s: %s", priv->argv[0], error->message);
 
239
    g_error_free (error);
 
240
    if (context)
 
241
      sn_launcher_context_complete (context);
 
242
 
 
243
    priv->active = NULL;
 
244
    g_strfreev (priv->argv);
 
245
    return FALSE;
 
246
  }
 
247
 
 
248
  launcher_menu_application_set_pid (app, pid);
 
249
  
 
250
  /* 
 
251
   * Let the program know that the launch has started, Sn apps get a longer
 
252
   * timeout
 
253
   */
 
254
  if (sn_enable)
 
255
    priv->tag = g_timeout_add (SN_TIMEOUT, (GSourceFunc)sn_timeout, startup);
 
256
  else
 
257
    priv->tag = g_timeout_add (TIMEOUT, (GSourceFunc)sn_timeout, startup);
 
258
 
 
259
  return TRUE;
 
260
}
 
261
#endif
 
262
 
 
263
gboolean
 
264
launcher_startup_launch_app (LauncherStartup          *startup, 
 
265
                             LauncherMenuApplication *app)
 
266
{
 
267
  LauncherStartupPrivate *priv;
 
268
  GError *error = NULL;
 
269
  SnLauncherContext *context = NULL;
 
270
  gboolean sn_enable = FALSE;;
 
271
  gboolean single_instance = FALSE;
 
272
  WnckWindow *window = NULL;
 
273
  gint pid;
 
274
 
 
275
  g_return_val_if_fail (LAUNCHER_IS_STARTUP (startup), FALSE);
 
276
  priv = startup->priv;
 
277
  
 
278
  priv->active = NULL;
 
279
 
 
280
  /* Check if a window by this name already exists */
 
281
  if ((pid = launcher_menu_application_get_pid (app)) > 0 && 0)
 
282
  {
 
283
    GList *windows = wnck_screen_get_windows (wnck_screen_get_default ());
 
284
    GList *w;
 
285
    for (w = windows; w; w = w->next)
 
286
    {
 
287
      gint id = wnck_window_get_pid (w->data);
 
288
      if (pid == id)
 
289
      {
 
290
        wnck_window_activate (w->data, CLUTTER_CURRENT_TIME);
 
291
        launcher_menu_application_set_window (app, w->data);
 
292
        g_debug ("Found existing window, pid = %d", pid);
 
293
        return TRUE;
 
294
      }
 
295
    }
 
296
  }
 
297
  window = launcher_menu_application_get_window (app);
 
298
  if (WNCK_IS_WINDOW (window))
 
299
  {
 
300
    wnck_window_activate (window, CLUTTER_CURRENT_TIME);
 
301
    return TRUE;
 
302
  }
 
303
 
 
304
  /* Load the important settings from the desktop file if not already done */
 
305
  load_app_settings (app, &sn_enable, &single_instance, &priv->argv);
 
306
 
 
307
  if (sn_enable)
 
308
  {
 
309
    SnDisplay *sn_dpy;
 
310
    Display *display;
 
311
    int screen;
 
312
 
 
313
    display = priv->xdisplay;
 
314
    sn_dpy = priv->sn_display;
 
315
 
 
316
    screen = gdk_screen_get_number (gdk_screen_get_default ());
 
317
    
 
318
    context = sn_launcher_context_new (sn_dpy, screen);
 
319
 
 
320
    sn_launcher_context_set_name (context,
 
321
                                launcher_menu_application_get_name (app));
 
322
    sn_launcher_context_set_binary_name (context, priv->argv[0]);
 
323
 
 
324
    sn_launcher_context_initiate (context,
 
325
                                  g_get_prgname () ?: "unknown",
 
326
                                  priv->argv[0],
 
327
                                  CLUTTER_CURRENT_TIME);
 
328
  }
 
329
 
 
330
  /* Execute the program */
 
331
  if (!gdk_spawn_on_screen (gdk_screen_get_default (),
 
332
                            NULL, priv->argv, NULL,
 
333
                            G_SPAWN_SEARCH_PATH,
 
334
                            child_setup,
 
335
                            context,
 
336
                            &pid,
 
337
                            &error))
 
338
  {
 
339
    g_warning ("Cannot launch %s: %s", priv->argv[0], error->message);
 
340
    g_error_free (error);
 
341
    if (context)
 
342
      sn_launcher_context_complete (context);
 
343
 
 
344
    priv->active = NULL;
 
345
    g_strfreev (priv->argv);
 
346
    return FALSE;
 
347
  }
 
348
 
 
349
  launcher_menu_application_set_pid (app, pid);
 
350
  
 
351
  /* 
 
352
   * Let the program know that the launch has started, Sn apps get a longer
 
353
   * timeout
 
354
   */
 
355
  if (sn_enable)
 
356
    priv->tag = g_timeout_add (SN_TIMEOUT, (GSourceFunc)sn_timeout, startup);
 
357
  else
 
358
    priv->tag = g_timeout_add (TIMEOUT, (GSourceFunc)sn_timeout, startup);
 
359
 
 
360
  return TRUE;}
 
361
 
 
362
/* 
 
363
 * Startup monitoring functions 
 
364
 */
 
365
 
 
366
static void
 
367
monitor_event_func (SnMonitorEvent *event, LauncherStartup *startup)
 
368
{
 
369
  LauncherStartupPrivate *priv;
 
370
  SnStartupSequence *seq;
 
371
  const gchar *b_name;
 
372
 
 
373
  g_return_if_fail (LAUNCHER_IS_STARTUP (startup));
 
374
  priv = startup->priv;
 
375
 
 
376
  if (sn_monitor_event_get_type (event) != SN_MONITOR_EVENT_COMPLETED)
 
377
    return;
 
378
  
 
379
  /*if (!LAUNCHER_IS_ITEM (priv->active) || priv->argv == NULL)
 
380
    return;*/
 
381
 
 
382
  seq = sn_monitor_event_get_startup_sequence (event);
 
383
  b_name = sn_startup_sequence_get_binary_name (seq);
 
384
  
 
385
  if (b_name == NULL)
 
386
    return;
 
387
 
 
388
  if (strcmp (priv->argv[0], b_name) == 0)
 
389
  {
 
390
    g_source_remove (priv->tag);
 
391
 
 
392
    /* 
 
393
     * Give some time for the main animation, otherwise apps that start too
 
394
     * fast mess up the animation
 
395
     */
 
396
    priv->tag = g_timeout_add (1000, (GSourceFunc)sn_timeout, startup);
 
397
  }
 
398
}
 
399
 
 
400
static GdkFilterReturn
 
401
filter_func (GdkXEvent        *gdk_xevent,
 
402
             GdkEvent         *event,
 
403
             LauncherStartup *startup)
 
404
{
 
405
  XEvent *xevent;
 
406
  xevent = (XEvent *) gdk_xevent;
 
407
  gboolean ret;
 
408
 
 
409
  g_return_val_if_fail (LAUNCHER_IS_STARTUP (startup), GDK_FILTER_CONTINUE);
 
410
 
 
411
  ret = sn_display_process_event (startup->priv->sn_display, xevent);
 
412
 
 
413
  return GDK_FILTER_CONTINUE;
 
414
}
 
415
 
 
416
/* GObject functions */
 
417
static void
 
418
launcher_startup_dispose (GObject *object)
 
419
{
 
420
  G_OBJECT_CLASS (launcher_startup_parent_class)->dispose (object);
 
421
}
 
422
 
 
423
static void
 
424
launcher_startup_finalize (GObject *startup)
 
425
{
 
426
  LauncherStartupPrivate *priv;
 
427
  
 
428
  g_return_if_fail (LAUNCHER_IS_STARTUP (startup));
 
429
  priv = LAUNCHER_STARTUP (startup)->priv;
 
430
 
 
431
 
 
432
  G_OBJECT_CLASS (launcher_startup_parent_class)->finalize (startup);
 
433
}
 
434
 
 
435
 
 
436
static void
 
437
launcher_startup_class_init (LauncherStartupClass *klass)
 
438
{
 
439
  GObjectClass *obj_class = G_OBJECT_CLASS (klass);
 
440
 
 
441
  obj_class->finalize = launcher_startup_finalize;
 
442
  obj_class->dispose = launcher_startup_dispose;
 
443
 
 
444
  g_type_class_add_private (obj_class, sizeof (LauncherStartupPrivate)); 
 
445
}
 
446
 
 
447
static void
 
448
launcher_startup_init (LauncherStartup *startup)
 
449
{
 
450
  LauncherStartupPrivate *priv;
 
451
  SnMonitorContext *context;
 
452
  
 
453
  priv = startup->priv = LAUNCHER_STARTUP_GET_PRIVATE (startup);
 
454
 
 
455
  priv->argv = NULL;
 
456
  priv->xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
457
  priv->sn_display = sn_display_new (priv->xdisplay, NULL, NULL);
 
458
  
 
459
  context = sn_monitor_context_new (priv->sn_display,
 
460
                                    DefaultScreen (priv->xdisplay),
 
461
                                    (SnMonitorEventFunc)monitor_event_func,
 
462
                                    (gpointer)startup,
 
463
                                    NULL);
 
464
 
 
465
  /*
 
466
   * We have to select for property events on at least one root window (but
 
467
   * not all and INITIATE messages go to all root windows 
 
468
   */
 
469
  XSelectInput (priv->xdisplay, 
 
470
                DefaultRootWindow (priv->xdisplay), PropertyChangeMask);
 
471
  
 
472
  priv->root_window = gdk_window_lookup_for_display (
 
473
                            gdk_x11_lookup_xdisplay (priv->xdisplay), 0);
 
474
 
 
475
  gdk_window_add_filter (priv->root_window, 
 
476
                         (GdkFilterFunc)filter_func,
 
477
                         (gpointer)startup);
 
478
}
 
479
 
 
480
LauncherStartup*
 
481
launcher_startup_get_default (void)
 
482
{
 
483
  static LauncherStartup *startup = NULL;
 
484
  
 
485
  if (startup == NULL)
 
486
    startup = g_object_new (LAUNCHER_TYPE_STARTUP, 
 
487
                            NULL);
 
488
 
 
489
  return startup;
 
490
}