~ubuntu-branches/debian/jessie/glib2.0/jessie

« back to all changes in this revision

Viewing changes to gio/win32/gwin32directorymonitor.c

  • Committer: Bazaar Package Importer
  • Author(s): Gustavo Noronha Silva
  • Date: 2009-02-15 13:00:43 UTC
  • mfrom: (1.3.1 upstream) (69.1.10 intrepid)
  • Revision ID: james.westby@ubuntu.com-20090215130043-q47fbt3owmt42m2f
Tags: 2.18.4-2
* Release to unstable
* debian/rules:
- bump SHVER, since we are already forcing a 2.18.0 dependecy on the
  symbols introduced in the development versions
* debian/control.in:
- added Homepage and Vcs-* control fields

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* GIO - GLib Input, Output and Streaming Library
 
2
 * 
 
3
 * Copyright (C) 2006-2007 Red Hat, Inc.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General
 
16
 * Public License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 *
 
20
 * Author: Vlad Grecescu <b100dian@gmail.com>
 
21
 * 
 
22
 */
 
23
 
 
24
#define _WIN32_WINNT 0x0400
 
25
 
 
26
#include "config.h"
 
27
#include "gwin32directorymonitor.h"
 
28
#include "giomodule.h"
 
29
#include <windows.h>
 
30
 
 
31
G_DEFINE_TYPE_WITH_CODE (GWin32DirectoryMonitor,
 
32
                         g_win32_directory_monitor,
 
33
                         G_TYPE_LOCAL_DIRECTORY_MONITOR,
 
34
                         g_io_extension_point_implement (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME,
 
35
                                                         g_define_type_id,
 
36
                                                         "readdirectorychanges",
 
37
                                                         20))
 
38
 
 
39
struct _GWin32DirectoryMonitorPrivate {
 
40
  OVERLAPPED overlapped;
 
41
  DWORD buffer_allocated_bytes;
 
42
  gchar *file_notify_buffer;
 
43
  DWORD buffer_filled_bytes;
 
44
  HANDLE hDirectory;
 
45
  /* Needed in the APC where we only have this private struct */
 
46
  GFileMonitor *self;
 
47
};
 
48
 
 
49
static void g_win32_directory_monitor_finalize (GObject *base);
 
50
static gboolean g_win32_directory_monitor_cancel (GFileMonitor *base);
 
51
 
 
52
static GObject *g_win32_directory_monitor_constructor (GType                  type,
 
53
                                                       guint                  n_construct_properties,
 
54
                                                       GObjectConstructParam *construct_properties);
 
55
 
 
56
static gboolean
 
57
g_win32_directory_monitor_is_supported (void)
 
58
{
 
59
  return TRUE;
 
60
}
 
61
 
 
62
static void
 
63
g_win32_directory_monitor_finalize (GObject *base)
 
64
{
 
65
  GWin32DirectoryMonitor *self;
 
66
  self = G_WIN32_DIRECTORY_MONITOR (base);
 
67
  
 
68
  g_free (self->priv->file_notify_buffer);
 
69
  g_free (self->priv);
 
70
 
 
71
  if (G_OBJECT_CLASS (g_win32_directory_monitor_parent_class)->finalize)
 
72
    (*G_OBJECT_CLASS (g_win32_directory_monitor_parent_class)->finalize) (base);
 
73
}
 
74
 
 
75
static gboolean
 
76
g_win32_directory_monitor_cancel (GFileMonitor *base)
 
77
{
 
78
  GWin32DirectoryMonitor *self;
 
79
  self = G_WIN32_DIRECTORY_MONITOR (base);
 
80
 
 
81
  /* This triggers a last callback() with nBytes=0 */ 
 
82
  if (self->priv->hDirectory != INVALID_HANDLE_VALUE)
 
83
    CloseHandle (self->priv->hDirectory);
 
84
 
 
85
  if (G_FILE_MONITOR_CLASS (g_win32_directory_monitor_parent_class)->cancel)
 
86
    (*G_FILE_MONITOR_CLASS (g_win32_directory_monitor_parent_class)->cancel) (base);
 
87
  return TRUE;
 
88
}
 
89
 
 
90
static void CALLBACK 
 
91
g_win32_directory_monitor_callback (DWORD        error,
 
92
                                    DWORD        nBytes,
 
93
                                    LPOVERLAPPED lpOverlapped)
 
94
{
 
95
  gulong offset;
 
96
  PFILE_NOTIFY_INFORMATION pfile_notify_walker;
 
97
  gulong file_name_len;
 
98
  gchar *file_name;
 
99
  gchar *path;
 
100
  GFile *file;
 
101
  GWin32DirectoryMonitorPrivate *priv = (GWin32DirectoryMonitorPrivate *) lpOverlapped;
 
102
 
 
103
  static GFileMonitorEvent events[] =
 
104
    {
 
105
      0, 
 
106
      G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_ADDED            */
 
107
      G_FILE_MONITOR_EVENT_DELETED, /* FILE_ACTION_REMOVED          */
 
108
      G_FILE_MONITOR_EVENT_CHANGED, /* FILE_ACTION_MODIFIED         */
 
109
      G_FILE_MONITOR_EVENT_DELETED, /* FILE_ACTION_RENAMED_OLD_NAME */
 
110
      G_FILE_MONITOR_EVENT_CREATED, /* FILE_ACTION_RENAMED_NEW_NAME */
 
111
    };
 
112
 
 
113
  if (!nBytes) /* Monitor was cancelled/finalized */
 
114
    return;
 
115
 
 
116
  if (g_file_monitor_is_cancelled (G_FILE_MONITOR (priv->self)))
 
117
    return; /* and ReadDirectoryChangesW doesn't get called this time */
 
118
 
 
119
  offset = 0;
 
120
  do {
 
121
    pfile_notify_walker = (PFILE_NOTIFY_INFORMATION)(priv->file_notify_buffer + offset);
 
122
    offset += pfile_notify_walker->NextEntryOffset;
 
123
    file_name = g_utf16_to_utf8 (pfile_notify_walker->FileName, pfile_notify_walker->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
 
124
    path = g_build_filename(G_LOCAL_DIRECTORY_MONITOR (priv->self)->dirname, file_name, NULL);
 
125
    file = g_file_new_for_path (path);
 
126
    g_file_monitor_emit_event (priv->self, file, NULL, events [pfile_notify_walker->Action]);
 
127
    g_object_unref (file);
 
128
    g_free (path);
 
129
    g_free (file_name);
 
130
  } while (pfile_notify_walker->NextEntryOffset);
 
131
 
 
132
  ReadDirectoryChangesW (priv->hDirectory,
 
133
                         (gpointer)priv->file_notify_buffer,
 
134
                         priv->buffer_allocated_bytes,
 
135
                         FALSE, 
 
136
                         FILE_NOTIFY_CHANGE_FILE_NAME |
 
137
                         FILE_NOTIFY_CHANGE_DIR_NAME |
 
138
                         FILE_NOTIFY_CHANGE_ATTRIBUTES |
 
139
                         FILE_NOTIFY_CHANGE_SIZE,
 
140
                         &priv->buffer_filled_bytes,
 
141
                         &priv->overlapped,
 
142
                         g_win32_directory_monitor_callback);
 
143
}
 
144
 
 
145
static GObject *
 
146
g_win32_directory_monitor_constructor (GType                  type,
 
147
                                       guint                  n_construct_properties,
 
148
                                       GObjectConstructParam *construct_properties) {
 
149
  GObject *obj;
 
150
  GWin32DirectoryMonitorClass *klass;
 
151
  GObjectClass *parent_class;
 
152
  GWin32DirectoryMonitor *self;
 
153
  wchar_t *wdirname;
 
154
  gboolean result;
 
155
 
 
156
  klass = G_WIN32_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_WIN32_DIRECTORY_MONITOR));
 
157
  parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
 
158
  obj = parent_class->constructor (type, n_construct_properties, construct_properties);
 
159
  self = G_WIN32_DIRECTORY_MONITOR (obj);
 
160
  wdirname = g_utf8_to_utf16 (G_LOCAL_DIRECTORY_MONITOR (obj)->dirname, -1, NULL, NULL, NULL);
 
161
 
 
162
  self->priv->hDirectory = CreateFileW (wdirname,
 
163
                                        FILE_LIST_DIRECTORY,
 
164
                                        FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, 
 
165
 
 
166
                                        NULL,
 
167
                                        OPEN_EXISTING,
 
168
                                        FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
 
169
                                        NULL); 
 
170
  g_free (wdirname);
 
171
  if (self->priv->hDirectory == INVALID_HANDLE_VALUE)
 
172
    {
 
173
      /* Ignore errors */
 
174
      return obj;
 
175
    }
 
176
 
 
177
  result = ReadDirectoryChangesW (self->priv->hDirectory,
 
178
                                  (gpointer)self->priv->file_notify_buffer,
 
179
                                  self->priv->buffer_allocated_bytes,
 
180
                                  FALSE, 
 
181
                                  FILE_NOTIFY_CHANGE_FILE_NAME |
 
182
                                  FILE_NOTIFY_CHANGE_DIR_NAME |
 
183
                                  FILE_NOTIFY_CHANGE_ATTRIBUTES |
 
184
                                  FILE_NOTIFY_CHANGE_SIZE,
 
185
                                  &self->priv->buffer_filled_bytes,
 
186
                                  &self->priv->overlapped,
 
187
                                  g_win32_directory_monitor_callback);
 
188
  /* Ignore errors */
 
189
 
 
190
  return obj;
 
191
}
 
192
 
 
193
static void 
 
194
g_win32_directory_monitor_class_init (GWin32DirectoryMonitorClass *klass)
 
195
{
 
196
  g_win32_directory_monitor_parent_class = g_type_class_peek_parent (klass);
 
197
 
 
198
  G_OBJECT_CLASS (klass)->constructor = g_win32_directory_monitor_constructor;
 
199
  G_OBJECT_CLASS (klass)->finalize = g_win32_directory_monitor_finalize;
 
200
  G_FILE_MONITOR_CLASS (klass)->cancel = g_win32_directory_monitor_cancel;
 
201
 
 
202
  G_LOCAL_DIRECTORY_MONITOR_CLASS (klass)->mount_notify = FALSE;
 
203
  G_LOCAL_DIRECTORY_MONITOR_CLASS (klass)->is_supported = g_win32_directory_monitor_is_supported;
 
204
}
 
205
 
 
206
static void
 
207
g_win32_directory_monitor_init (GWin32DirectoryMonitor *self) 
 
208
{
 
209
  self->priv = (GWin32DirectoryMonitorPrivate*)g_new0 (GWin32DirectoryMonitorPrivate, 1);
 
210
  g_assert (self->priv != 0);
 
211
        
 
212
  self->priv->buffer_allocated_bytes = 32768;
 
213
  self->priv->file_notify_buffer = g_new0 (gchar, self->priv->buffer_allocated_bytes);
 
214
  g_assert (self->priv->file_notify_buffer);
 
215
        
 
216
  self->priv->self = G_FILE_MONITOR (self);
 
217
}