You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

942 lines
20 KiB

  1. /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
  2. /* Muffin utilities */
  3. /*
  4. * Copyright (C) 2001 Havoc Pennington
  5. * Copyright (C) 2005 Elijah Newren
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of the
  10. * License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
  20. * 02110-1335, USA.
  21. */
  22. /**
  23. * SECTION:util
  24. * @title: Utility functions
  25. * @short_description: Miscellaneous utility functions
  26. */
  27. #ifndef _GNU_SOURCE
  28. #define _GNU_SOURCE
  29. #endif
  30. #define _POSIX_C_SOURCE 200112L /* for fdopen() */
  31. #include <config.h>
  32. #include <meta/common.h>
  33. #include <meta/util.h>
  34. #include <meta/main.h>
  35. #include <clutter/clutter.h> /* For clutter_threads_add_repaint_func() */
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <unistd.h>
  39. #include <errno.h>
  40. #include <string.h>
  41. #include <X11/Xlib.h> /* must explicitly be included for Solaris; #326746 */
  42. #include <X11/Xutil.h> /* Just for the definition of the various gravities */
  43. #ifdef WITH_VERBOSE_MODE
  44. static void
  45. meta_topic_real_valist (MetaDebugTopic topic,
  46. const char *format,
  47. va_list args);
  48. #endif
  49. #ifdef HAVE_BACKTRACE
  50. #include <execinfo.h>
  51. void
  52. meta_print_backtrace (void)
  53. {
  54. void *bt[500];
  55. int bt_size;
  56. int i;
  57. char **syms;
  58. bt_size = backtrace (bt, 500);
  59. syms = backtrace_symbols (bt, bt_size);
  60. i = 0;
  61. while (i < bt_size)
  62. {
  63. meta_verbose (" %s\n", syms[i]);
  64. ++i;
  65. }
  66. free (syms);
  67. }
  68. #else
  69. void
  70. meta_print_backtrace (void)
  71. {
  72. meta_verbose ("Not compiled with backtrace support\n");
  73. }
  74. #endif
  75. static gint verbose_topics = 0;
  76. static gboolean is_debugging = FALSE;
  77. static gboolean replace_current = FALSE;
  78. static int no_prefix = 0;
  79. #ifdef WITH_VERBOSE_MODE
  80. static FILE* logfile = NULL;
  81. static void
  82. ensure_logfile (void)
  83. {
  84. if (logfile == NULL && g_getenv ("MUFFIN_USE_LOGFILE"))
  85. {
  86. char *filename = NULL;
  87. char *tmpl;
  88. int fd;
  89. GError *err;
  90. tmpl = g_strdup_printf ("muffin-%d-debug-log-XXXXXX",
  91. (int) getpid ());
  92. err = NULL;
  93. fd = g_file_open_tmp (tmpl,
  94. &filename,
  95. &err);
  96. g_free (tmpl);
  97. if (err != NULL)
  98. {
  99. meta_warning (_("Failed to open debug log: %s\n"),
  100. err->message);
  101. g_error_free (err);
  102. return;
  103. }
  104. logfile = fdopen (fd, "w");
  105. if (logfile == NULL)
  106. {
  107. meta_warning (_("Failed to fdopen() log file %s: %s\n"),
  108. filename, strerror (errno));
  109. close (fd);
  110. }
  111. else
  112. {
  113. g_printerr (_("Opened log file %s\n"), filename);
  114. }
  115. g_free (filename);
  116. }
  117. }
  118. #endif
  119. gboolean
  120. meta_is_verbose (void)
  121. {
  122. return verbose_topics != 0;
  123. }
  124. void
  125. meta_set_verbose (gboolean setting)
  126. {
  127. #ifndef WITH_VERBOSE_MODE
  128. if (setting)
  129. meta_fatal (_("Muffin was compiled without support for verbose mode\n"));
  130. #else
  131. if (setting)
  132. ensure_logfile ();
  133. #endif
  134. if (setting)
  135. meta_add_verbose_topic (META_DEBUG_VERBOSE);
  136. else
  137. meta_remove_verbose_topic (META_DEBUG_VERBOSE);
  138. }
  139. /**
  140. * meta_add_verbose_topic:
  141. * @topic: Topic for which logging will be started
  142. *
  143. * Ensure log messages for the given topic @topic
  144. * will be printed.
  145. */
  146. void
  147. meta_add_verbose_topic (MetaDebugTopic topic)
  148. {
  149. if (verbose_topics == META_DEBUG_VERBOSE)
  150. return;
  151. if (topic == META_DEBUG_VERBOSE)
  152. verbose_topics = META_DEBUG_VERBOSE;
  153. else
  154. verbose_topics |= topic;
  155. }
  156. /**
  157. * meta_remove_verbose_topic:
  158. * @topic: Topic for which logging will be stopped
  159. *
  160. * Stop printing log messages for the given topic @topic. Note
  161. * that this method does not stack with meta_add_verbose_topic();
  162. * i.e. if two calls to meta_add_verbose_topic() for the same
  163. * topic are made, one call to meta_remove_verbose_topic() will
  164. * remove it.
  165. */
  166. void
  167. meta_remove_verbose_topic (MetaDebugTopic topic)
  168. {
  169. if (topic == META_DEBUG_VERBOSE)
  170. verbose_topics = 0;
  171. else
  172. verbose_topics &= ~topic;
  173. }
  174. gboolean
  175. meta_is_debugging (void)
  176. {
  177. return is_debugging;
  178. }
  179. void
  180. meta_set_debugging (gboolean setting)
  181. {
  182. #ifdef WITH_VERBOSE_MODE
  183. if (setting)
  184. ensure_logfile ();
  185. #endif
  186. is_debugging = setting;
  187. }
  188. gboolean
  189. meta_get_replace_current_wm (void)
  190. {
  191. return replace_current;
  192. }
  193. void
  194. meta_set_replace_current_wm (gboolean setting)
  195. {
  196. replace_current = setting;
  197. }
  198. char *
  199. meta_g_utf8_strndup (const gchar *src,
  200. gsize n)
  201. {
  202. const gchar *s = src;
  203. while (n && *s)
  204. {
  205. s = g_utf8_next_char (s);
  206. n--;
  207. }
  208. return g_strndup (src, s - src);
  209. }
  210. static int
  211. utf8_fputs (const char *str,
  212. FILE *f)
  213. {
  214. char *l;
  215. int retval;
  216. l = g_locale_from_utf8 (str, -1, NULL, NULL, NULL);
  217. if (l == NULL)
  218. retval = fputs (str, f); /* just print it anyway, better than nothing */
  219. else
  220. retval = fputs (l, f);
  221. g_free (l);
  222. return retval;
  223. }
  224. /**
  225. * meta_free_gslist_and_elements: (skip)
  226. *
  227. */
  228. void
  229. meta_free_gslist_and_elements (GSList *list_to_deep_free)
  230. {
  231. g_slist_foreach (list_to_deep_free,
  232. (void (*)(gpointer,gpointer))&g_free, /* ew, for ugly */
  233. NULL);
  234. g_slist_free (list_to_deep_free);
  235. }
  236. #ifdef WITH_VERBOSE_MODE
  237. void
  238. meta_debug_spew_real (const char *format, ...)
  239. {
  240. va_list args;
  241. gchar *str;
  242. FILE *out;
  243. g_return_if_fail (format != NULL);
  244. if (!is_debugging)
  245. return;
  246. va_start (args, format);
  247. str = g_strdup_vprintf (format, args);
  248. va_end (args);
  249. out = logfile ? logfile : stderr;
  250. if (no_prefix == 0)
  251. utf8_fputs ("Window manager: ", out);
  252. utf8_fputs (str, out);
  253. fflush (out);
  254. g_free (str);
  255. }
  256. #endif /* WITH_VERBOSE_MODE */
  257. #ifdef WITH_VERBOSE_MODE
  258. void
  259. meta_verbose_real (const char *format, ...)
  260. {
  261. va_list args;
  262. va_start (args, format);
  263. meta_topic_real_valist (META_DEBUG_VERBOSE, format, args);
  264. va_end (args);
  265. }
  266. #endif /* WITH_VERBOSE_MODE */
  267. #ifdef WITH_VERBOSE_MODE
  268. static const char*
  269. topic_name (MetaDebugTopic topic)
  270. {
  271. switch (topic)
  272. {
  273. case META_DEBUG_FOCUS:
  274. return "FOCUS";
  275. case META_DEBUG_WORKAREA:
  276. return "WORKAREA";
  277. case META_DEBUG_STACK:
  278. return "STACK";
  279. case META_DEBUG_THEMES:
  280. return "THEMES";
  281. case META_DEBUG_SM:
  282. return "SM";
  283. case META_DEBUG_EVENTS:
  284. return "EVENTS";
  285. case META_DEBUG_WINDOW_STATE:
  286. return "WINDOW_STATE";
  287. case META_DEBUG_WINDOW_OPS:
  288. return "WINDOW_OPS";
  289. case META_DEBUG_PLACEMENT:
  290. return "PLACEMENT";
  291. case META_DEBUG_GEOMETRY:
  292. return "GEOMETRY";
  293. case META_DEBUG_PING:
  294. return "PING";
  295. case META_DEBUG_XINERAMA:
  296. return "XINERAMA";
  297. case META_DEBUG_KEYBINDINGS:
  298. return "KEYBINDINGS";
  299. case META_DEBUG_SYNC:
  300. return "SYNC";
  301. case META_DEBUG_ERRORS:
  302. return "ERRORS";
  303. case META_DEBUG_STARTUP:
  304. return "STARTUP";
  305. case META_DEBUG_PREFS:
  306. return "PREFS";
  307. case META_DEBUG_GROUPS:
  308. return "GROUPS";
  309. case META_DEBUG_RESIZING:
  310. return "RESIZING";
  311. case META_DEBUG_SHAPES:
  312. return "SHAPES";
  313. case META_DEBUG_COMPOSITOR:
  314. return "COMPOSITOR";
  315. case META_DEBUG_EDGE_RESISTANCE:
  316. return "EDGE_RESISTANCE";
  317. case META_DEBUG_VERBOSE:
  318. return "VERBOSE";
  319. }
  320. return "WM";
  321. }
  322. static int sync_count = 0;
  323. static void
  324. meta_topic_real_valist (MetaDebugTopic topic,
  325. const char *format,
  326. va_list args)
  327. {
  328. gchar *str;
  329. FILE *out;
  330. g_return_if_fail (format != NULL);
  331. if (verbose_topics == 0
  332. || (topic == META_DEBUG_VERBOSE && verbose_topics != META_DEBUG_VERBOSE)
  333. || (!(verbose_topics & topic)))
  334. return;
  335. str = g_strdup_vprintf (format, args);
  336. out = logfile ? logfile : stderr;
  337. if (no_prefix == 0)
  338. fprintf (out, "%s: ", topic_name (topic));
  339. if (topic == META_DEBUG_SYNC)
  340. {
  341. ++sync_count;
  342. fprintf (out, "%d: ", sync_count);
  343. }
  344. utf8_fputs (str, out);
  345. fflush (out);
  346. g_free (str);
  347. }
  348. void
  349. meta_topic_real (MetaDebugTopic topic,
  350. const char *format,
  351. ...)
  352. {
  353. va_list args;
  354. va_start (args, format);
  355. meta_topic_real_valist (topic, format, args);
  356. va_end (args);
  357. }
  358. #endif /* WITH_VERBOSE_MODE */
  359. void
  360. meta_bug (const char *format, ...)
  361. {
  362. va_list args;
  363. gchar *str;
  364. FILE *out;
  365. g_return_if_fail (format != NULL);
  366. va_start (args, format);
  367. str = g_strdup_vprintf (format, args);
  368. va_end (args);
  369. #ifdef WITH_VERBOSE_MODE
  370. out = logfile ? logfile : stderr;
  371. #else
  372. out = stderr;
  373. #endif
  374. if (no_prefix == 0)
  375. utf8_fputs ("Bug in window manager: ", out);
  376. utf8_fputs (str, out);
  377. fflush (out);
  378. g_free (str);
  379. meta_print_backtrace ();
  380. /* stop us in a debugger */
  381. abort ();
  382. }
  383. void
  384. meta_warning (const char *format, ...)
  385. {
  386. va_list args;
  387. gchar *str;
  388. FILE *out;
  389. g_return_if_fail (format != NULL);
  390. va_start (args, format);
  391. str = g_strdup_vprintf (format, args);
  392. va_end (args);
  393. #ifdef WITH_VERBOSE_MODE
  394. out = logfile ? logfile : stderr;
  395. #else
  396. out = stderr;
  397. #endif
  398. if (no_prefix == 0)
  399. utf8_fputs ("Window manager warning: ", out);
  400. utf8_fputs (str, out);
  401. fflush (out);
  402. g_free (str);
  403. }
  404. void
  405. meta_fatal (const char *format, ...)
  406. {
  407. va_list args;
  408. gchar *str;
  409. FILE *out;
  410. g_return_if_fail (format != NULL);
  411. va_start (args, format);
  412. str = g_strdup_vprintf (format, args);
  413. va_end (args);
  414. #ifdef WITH_VERBOSE_MODE
  415. out = logfile ? logfile : stderr;
  416. #else
  417. out = stderr;
  418. #endif
  419. if (no_prefix == 0)
  420. utf8_fputs ("Window manager error: ", out);
  421. utf8_fputs (str, out);
  422. fflush (out);
  423. g_free (str);
  424. meta_exit (META_EXIT_ERROR);
  425. }
  426. void
  427. meta_push_no_msg_prefix (void)
  428. {
  429. ++no_prefix;
  430. }
  431. void
  432. meta_pop_no_msg_prefix (void)
  433. {
  434. g_return_if_fail (no_prefix > 0);
  435. --no_prefix;
  436. }
  437. void
  438. meta_exit (MetaExitCode code)
  439. {
  440. exit (code);
  441. }
  442. gint
  443. meta_unsigned_long_equal (gconstpointer v1,
  444. gconstpointer v2)
  445. {
  446. return *((const gulong*) v1) == *((const gulong*) v2);
  447. }
  448. guint
  449. meta_unsigned_long_hash (gconstpointer v)
  450. {
  451. gulong val = * (const gulong *) v;
  452. /* I'm not sure this works so well. */
  453. #if GLIB_SIZEOF_LONG > 4
  454. return (guint) (val ^ (val >> 32));
  455. #else
  456. return val;
  457. #endif
  458. }
  459. const char*
  460. meta_gravity_to_string (int gravity)
  461. {
  462. switch (gravity)
  463. {
  464. case NorthWestGravity:
  465. return "NorthWestGravity";
  466. break;
  467. case NorthGravity:
  468. return "NorthGravity";
  469. break;
  470. case NorthEastGravity:
  471. return "NorthEastGravity";
  472. break;
  473. case WestGravity:
  474. return "WestGravity";
  475. break;
  476. case CenterGravity:
  477. return "CenterGravity";
  478. break;
  479. case EastGravity:
  480. return "EastGravity";
  481. break;
  482. case SouthWestGravity:
  483. return "SouthWestGravity";
  484. break;
  485. case SouthGravity:
  486. return "SouthGravity";
  487. break;
  488. case SouthEastGravity:
  489. return "SouthEastGravity";
  490. break;
  491. case StaticGravity:
  492. return "StaticGravity";
  493. break;
  494. default:
  495. return "NorthWestGravity";
  496. break;
  497. }
  498. }
  499. /* Command line arguments are passed in the locale encoding; in almost
  500. * all cases, we'd hope that is UTF-8 and no conversion is necessary.
  501. * If it's not UTF-8, then it's possible that the message isn't
  502. * representable in the locale encoding.
  503. */
  504. static void
  505. append_argument (GPtrArray *args,
  506. const char *arg)
  507. {
  508. char *locale_arg = g_locale_from_utf8 (arg, -1, NULL, NULL, NULL);
  509. /* This is cheesy, but it's better to have a few ???'s in the dialog
  510. * for an unresponsive application than no dialog at all appear */
  511. if (!locale_arg)
  512. locale_arg = g_strdup ("???");
  513. g_ptr_array_add (args, locale_arg);
  514. }
  515. /**
  516. * meta_show_dialog: (skip)
  517. *
  518. */
  519. GPid
  520. meta_show_dialog (const char *type,
  521. const char *message,
  522. const char *timeout,
  523. const char *display,
  524. const char *ok_text,
  525. const char *cancel_text,
  526. const int transient_for,
  527. GSList *columns,
  528. GSList *entries)
  529. {
  530. GError *error = NULL;
  531. GSList *tmp;
  532. GPid child_pid;
  533. GPtrArray *args;
  534. args = g_ptr_array_new ();
  535. append_argument (args, "zenity");
  536. append_argument (args, type);
  537. append_argument (args, "--display");
  538. append_argument (args, display);
  539. append_argument (args, "--class");
  540. append_argument (args, "muffin-dialog");
  541. append_argument (args, "--title");
  542. append_argument (args, "");
  543. append_argument (args, "--text");
  544. append_argument (args, message);
  545. if (timeout)
  546. {
  547. append_argument (args, "--timeout");
  548. append_argument (args, timeout);
  549. }
  550. if (ok_text)
  551. {
  552. append_argument (args, "--ok-label");
  553. append_argument (args, ok_text);
  554. }
  555. if (cancel_text)
  556. {
  557. append_argument (args, "--cancel-label");
  558. append_argument (args, cancel_text);
  559. }
  560. tmp = columns;
  561. while (tmp)
  562. {
  563. append_argument (args, "--column");
  564. append_argument (args, tmp->data);
  565. tmp = tmp->next;
  566. }
  567. tmp = entries;
  568. while (tmp)
  569. {
  570. append_argument (args, tmp->data);
  571. tmp = tmp->next;
  572. }
  573. g_ptr_array_add (args, NULL); /* NULL-terminate */
  574. if (transient_for)
  575. {
  576. gchar *env = g_strdup_printf("%d", transient_for);
  577. setenv ("WINDOWID", env, 1);
  578. g_free (env);
  579. }
  580. g_spawn_async (
  581. "/",
  582. (gchar**) args->pdata,
  583. NULL,
  584. G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
  585. NULL, NULL,
  586. &child_pid,
  587. &error
  588. );
  589. if (transient_for)
  590. unsetenv ("WINDOWID");
  591. g_ptr_array_free (args, TRUE);
  592. if (error)
  593. {
  594. meta_warning ("%s\n", error->message);
  595. g_error_free (error);
  596. }
  597. return child_pid;
  598. }
  599. /***************************************************************************
  600. * Later functions: like idles but integrated with the Clutter repaint loop
  601. ***************************************************************************/
  602. static guint last_later_id = 0;
  603. typedef struct
  604. {
  605. guint id;
  606. guint ref_count;
  607. MetaLaterType when;
  608. GSourceFunc func;
  609. gpointer data;
  610. GDestroyNotify notify;
  611. int source;
  612. gboolean run_once;
  613. } MetaLater;
  614. static GSList *laters = NULL;
  615. /* This is a dummy timeline used to get the Clutter master clock running */
  616. static ClutterTimeline *later_timeline;
  617. static guint later_repaint_func = 0;
  618. static void ensure_later_repaint_func (void);
  619. static void
  620. unref_later (MetaLater *later)
  621. {
  622. if (--later->ref_count == 0)
  623. {
  624. if (later->notify)
  625. {
  626. later->notify (later->data);
  627. later->notify = NULL;
  628. }
  629. g_slice_free (MetaLater, later);
  630. }
  631. }
  632. static void
  633. destroy_later (MetaLater *later)
  634. {
  635. if (later->source)
  636. {
  637. g_source_remove (later->source);
  638. later->source = 0;
  639. }
  640. later->func = NULL;
  641. unref_later (later);
  642. }
  643. /* Used to sort the list of laters with the highest priority
  644. * functions first.
  645. */
  646. static int
  647. compare_laters (gconstpointer a,
  648. gconstpointer b)
  649. {
  650. return ((const MetaLater *)a)->when - ((const MetaLater *)b)->when;
  651. }
  652. static gboolean
  653. run_repaint_laters (gpointer data)
  654. {
  655. GSList *laters_copy;
  656. GSList *l;
  657. gboolean keep_timeline_running = FALSE;
  658. laters_copy = NULL;
  659. for (l = laters; l; l = l->next)
  660. {
  661. MetaLater *later = l->data;
  662. if (later->source == 0 ||
  663. (later->when <= META_LATER_BEFORE_REDRAW && !later->run_once))
  664. {
  665. later->ref_count++;
  666. laters_copy = g_slist_prepend (laters_copy, later);
  667. }
  668. }
  669. laters_copy = g_slist_reverse (laters_copy);
  670. for (l = laters_copy; l; l = l->next)
  671. {
  672. MetaLater *later = l->data;
  673. if (later->func && later->func (later->data))
  674. {
  675. if (later->source == 0)
  676. keep_timeline_running = TRUE;
  677. }
  678. else
  679. meta_later_remove (later->id);
  680. unref_later (later);
  681. }
  682. if (!keep_timeline_running)
  683. clutter_timeline_stop (later_timeline);
  684. g_slist_free (laters_copy);
  685. /* Just keep the repaint func around - it's cheap if the list is empty */
  686. return TRUE;
  687. }
  688. static void
  689. ensure_later_repaint_func (void)
  690. {
  691. if (!later_timeline)
  692. later_timeline = clutter_timeline_new (G_MAXUINT);
  693. if (later_repaint_func == 0)
  694. later_repaint_func = clutter_threads_add_repaint_func (run_repaint_laters,
  695. NULL, NULL);
  696. /* Make sure the repaint function gets run */
  697. clutter_timeline_start (later_timeline);
  698. }
  699. static gboolean
  700. call_idle_later (gpointer data)
  701. {
  702. MetaLater *later = data;
  703. if (!later->func (later->data))
  704. {
  705. meta_later_remove (later->id);
  706. return FALSE;
  707. }
  708. else
  709. {
  710. later->run_once = TRUE;
  711. return TRUE;
  712. }
  713. }
  714. /**
  715. * meta_later_add:
  716. * @when: enumeration value determining the phase at which to run the callback
  717. * @func: callback to run later
  718. * @data: data to pass to the callback
  719. * @notify: function to call to destroy @data when it is no longer in use, or %NULL
  720. *
  721. * Sets up a callback to be called at some later time. @when determines the
  722. * particular later occasion at which it is called. This is much like g_idle_add(),
  723. * except that the functions interact properly with clutter event handling.
  724. * If a "later" function is added from a clutter event handler, and is supposed
  725. * to be run before the stage is redrawn, it will be run before that redraw
  726. * of the stage, not the next one.
  727. *
  728. * Return value: an integer ID (guaranteed to be non-zero) that can be used
  729. * to cancel the callback and prevent it from being run.
  730. */
  731. guint
  732. meta_later_add (MetaLaterType when,
  733. GSourceFunc func,
  734. gpointer data,
  735. GDestroyNotify notify)
  736. {
  737. MetaLater *later = g_slice_new0 (MetaLater);
  738. later->id = ++last_later_id;
  739. later->ref_count = 1;
  740. later->when = when;
  741. later->func = func;
  742. later->data = data;
  743. later->notify = notify;
  744. laters = g_slist_insert_sorted (laters, later, compare_laters);
  745. switch (when)
  746. {
  747. case META_LATER_RESIZE:
  748. /* We add this one two ways - as a high-priority idle and as a
  749. * repaint func. If we are in a clutter event callback, the repaint
  750. * handler will get hit first, and we'll take care of this function
  751. * there so it gets called before the stage is redrawn, even if
  752. * we haven't gotten back to the main loop. Otherwise, the idle
  753. * handler will get hit first and we want to call this function
  754. * there so it will happen before GTK+ repaints.
  755. */
  756. later->source = g_idle_add_full (META_PRIORITY_RESIZE, call_idle_later, later, NULL);
  757. ensure_later_repaint_func ();
  758. break;
  759. case META_LATER_CALC_SHOWING:
  760. case META_LATER_CHECK_FULLSCREEN:
  761. case META_LATER_SYNC_STACK:
  762. case META_LATER_BEFORE_REDRAW:
  763. ensure_later_repaint_func ();
  764. break;
  765. case META_LATER_IDLE:
  766. later->source = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, call_idle_later, later, NULL);
  767. break;
  768. }
  769. return later->id;
  770. }
  771. /**
  772. * meta_later_remove:
  773. * @later_id: the integer ID returned from meta_later_add()
  774. *
  775. * Removes a callback added with meta_later_add()
  776. */
  777. void
  778. meta_later_remove (guint later_id)
  779. {
  780. GSList *l;
  781. for (l = laters; l; l = l->next)
  782. {
  783. MetaLater *later = l->data;
  784. if (later->id == later_id)
  785. {
  786. laters = g_slist_delete_link (laters, l);
  787. /* If this was a "repaint func" later, we just let the
  788. * repaint func run and get removed
  789. */
  790. destroy_later (later);
  791. return;
  792. }
  793. }
  794. }
  795. /* eof util.c */