(root)/
glib-2.79.0/
gio/
gpollfilemonitor.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   * 
       3   * Copyright (C) 2006-2007 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: Alexander Larsson <alexl@redhat.com>
      21   */
      22  
      23  #include "config.h"
      24  #include <string.h>
      25  
      26  #include "gpollfilemonitor.h"
      27  #include "gfile.h"
      28  #include "gfilemonitor.h"
      29  #include "gfileinfo.h"
      30  
      31  
      32  static gboolean g_poll_file_monitor_cancel (GFileMonitor* monitor);
      33  static void schedule_poll_timeout (GPollFileMonitor* poll_monitor);
      34  
      35  struct _GPollFileMonitor
      36  {
      37    GFileMonitor parent_instance;
      38    GFile *file;
      39    GFileInfo *last_info;
      40    GSource *timeout;
      41  };
      42  
      43  #define POLL_TIME_SECS 5
      44  
      45  #define g_poll_file_monitor_get_type _g_poll_file_monitor_get_type
      46  G_DEFINE_TYPE (GPollFileMonitor, g_poll_file_monitor, G_TYPE_FILE_MONITOR)
      47  
      48  static void
      49  g_poll_file_monitor_finalize (GObject* object)
      50  {
      51    GPollFileMonitor* poll_monitor;
      52    
      53    poll_monitor = G_POLL_FILE_MONITOR (object);
      54  
      55    g_poll_file_monitor_cancel (G_FILE_MONITOR (poll_monitor));
      56    g_object_unref (poll_monitor->file);
      57    g_clear_object (&poll_monitor->last_info);
      58  
      59    G_OBJECT_CLASS (g_poll_file_monitor_parent_class)->finalize (object);
      60  }
      61  
      62  
      63  static void
      64  g_poll_file_monitor_class_init (GPollFileMonitorClass* klass)
      65  {
      66    GObjectClass* gobject_class = G_OBJECT_CLASS (klass);
      67    GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (klass);
      68    
      69    gobject_class->finalize = g_poll_file_monitor_finalize;
      70  
      71    file_monitor_class->cancel = g_poll_file_monitor_cancel;
      72  }
      73  
      74  static void
      75  g_poll_file_monitor_init (GPollFileMonitor* poll_monitor)
      76  {
      77  }
      78  
      79  static int
      80  calc_event_type (GFileInfo *last,
      81  		 GFileInfo *new)
      82  {
      83    if (last == NULL && new == NULL)
      84      return -1;
      85  
      86    if (last == NULL && new != NULL)
      87      return G_FILE_MONITOR_EVENT_CREATED;
      88    
      89    if (last != NULL && new == NULL)
      90      return G_FILE_MONITOR_EVENT_DELETED;
      91  
      92    if (g_file_info_has_attribute (last, G_FILE_ATTRIBUTE_ETAG_VALUE) &&
      93        g_file_info_has_attribute (new, G_FILE_ATTRIBUTE_ETAG_VALUE) &&
      94        g_strcmp0 (g_file_info_get_etag (last), g_file_info_get_etag (new)) != 0)
      95      return G_FILE_MONITOR_EVENT_CHANGED;
      96    
      97    if (g_file_info_has_attribute (last, G_FILE_ATTRIBUTE_STANDARD_SIZE) &&
      98        g_file_info_has_attribute (new, G_FILE_ATTRIBUTE_STANDARD_SIZE) &&
      99        g_file_info_get_size (last) != g_file_info_get_size (new))
     100      return G_FILE_MONITOR_EVENT_CHANGED;
     101  
     102    return -1;
     103  }
     104  
     105  static void
     106  got_new_info (GObject      *source_object,
     107                GAsyncResult *res,
     108                gpointer      user_data)
     109  {
     110    GPollFileMonitor* poll_monitor = user_data;
     111    GFileInfo *info;
     112    int event;
     113  
     114    info = g_file_query_info_finish (poll_monitor->file, res, NULL);
     115  
     116    if (!g_file_monitor_is_cancelled (G_FILE_MONITOR (poll_monitor)))
     117      {
     118        event = calc_event_type (poll_monitor->last_info, info);
     119  
     120        if (event != -1)
     121  	{
     122  	  g_file_monitor_emit_event (G_FILE_MONITOR (poll_monitor),
     123  				     poll_monitor->file,
     124  				     NULL, event);
     125  	  /* We're polling so slowly anyway, so always emit the done hint */
     126  	  if (!g_file_monitor_is_cancelled (G_FILE_MONITOR (poll_monitor)) &&
     127               (event == G_FILE_MONITOR_EVENT_CHANGED || event == G_FILE_MONITOR_EVENT_CREATED))
     128  	    g_file_monitor_emit_event (G_FILE_MONITOR (poll_monitor),
     129  				       poll_monitor->file,
     130  				       NULL, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT);
     131  	}
     132        
     133        if (poll_monitor->last_info)
     134  	{
     135  	  g_object_unref (poll_monitor->last_info);
     136  	  poll_monitor->last_info = NULL;
     137  	}
     138        
     139        if (info)
     140  	poll_monitor->last_info = g_object_ref (info);
     141        
     142        schedule_poll_timeout (poll_monitor);
     143      }
     144  
     145    if (info)
     146      g_object_unref (info);
     147    
     148    g_object_unref (poll_monitor);
     149  }
     150  
     151  static gboolean
     152  poll_file_timeout (gpointer data)
     153  {
     154    GPollFileMonitor* poll_monitor = data;
     155  
     156    g_source_unref (poll_monitor->timeout);
     157    poll_monitor->timeout = NULL;
     158  
     159    g_file_query_info_async (poll_monitor->file, G_FILE_ATTRIBUTE_ETAG_VALUE "," G_FILE_ATTRIBUTE_STANDARD_SIZE,
     160  			 0, 0, NULL, got_new_info, g_object_ref (poll_monitor));
     161    
     162    return G_SOURCE_REMOVE;
     163  }
     164  
     165  static void
     166  schedule_poll_timeout (GPollFileMonitor* poll_monitor)
     167  {
     168    poll_monitor->timeout = g_timeout_source_new_seconds (POLL_TIME_SECS);
     169    g_source_set_callback (poll_monitor->timeout, poll_file_timeout, poll_monitor, NULL);
     170    g_source_attach (poll_monitor->timeout, g_main_context_get_thread_default ());
     171  }
     172  
     173  static void
     174  got_initial_info (GObject      *source_object,
     175                    GAsyncResult *res,
     176                    gpointer      user_data)
     177  {
     178    GPollFileMonitor* poll_monitor = user_data;
     179    GFileInfo *info;
     180  
     181    info = g_file_query_info_finish (poll_monitor->file, res, NULL);
     182  
     183    poll_monitor->last_info = info;
     184  
     185    if (!g_file_monitor_is_cancelled (G_FILE_MONITOR (poll_monitor)))
     186      schedule_poll_timeout (poll_monitor);
     187    
     188    g_object_unref (poll_monitor);
     189  }
     190  
     191  /**
     192   * _g_poll_file_monitor_new:
     193   * @file: a #GFile.
     194   * 
     195   * Polls @file for changes.
     196   * 
     197   * Returns: a new #GFileMonitor for the given #GFile. 
     198   **/
     199  GFileMonitor*
     200  _g_poll_file_monitor_new (GFile *file)
     201  {
     202    GPollFileMonitor* poll_monitor;
     203    
     204    poll_monitor = g_object_new (G_TYPE_POLL_FILE_MONITOR, NULL);
     205  
     206    poll_monitor->file = g_object_ref (file);
     207  
     208    g_file_query_info_async (file, G_FILE_ATTRIBUTE_ETAG_VALUE "," G_FILE_ATTRIBUTE_STANDARD_SIZE,
     209  			   0, 0, NULL, got_initial_info, g_object_ref (poll_monitor));
     210    
     211    return G_FILE_MONITOR (poll_monitor);
     212  }
     213  
     214  static gboolean
     215  g_poll_file_monitor_cancel (GFileMonitor* monitor)
     216  {
     217    GPollFileMonitor *poll_monitor = G_POLL_FILE_MONITOR (monitor);
     218    
     219    if (poll_monitor->timeout)
     220      {
     221        g_source_destroy (poll_monitor->timeout);
     222        g_source_unref (poll_monitor->timeout);
     223        poll_monitor->timeout = NULL;
     224      }
     225    
     226    return TRUE;
     227  }