📄 gtkselection.c
字号:
info->conversions[i].offset; buffer = info->conversions[i].data.data + info->conversions[i].offset; if (num_bytes > GTK_SELECTION_MAX_SIZE) { num_bytes = GTK_SELECTION_MAX_SIZE; info->conversions[i].offset += GTK_SELECTION_MAX_SIZE; } else info->conversions[i].offset = -2; }#ifdef DEBUG_SELECTION g_message ("INCR: put %d bytes (offset = %d) into window 0x%lx , property %ld", num_bytes, info->conversions[i].offset, GDK_WINDOW_XWINDOW(info->requestor), event->atom);#endif gdk_property_change (info->requestor, event->atom, info->conversions[i].data.type, info->conversions[i].data.format, GDK_PROP_MODE_REPLACE, buffer, (num_bytes + info->conversions[i].data.format/8 - 1) / (info->conversions[i].data.format/8)); if (info->conversions[i].offset == -2) { g_free (info->conversions[i].data.data); info->conversions[i].data.data = NULL; } if (num_bytes == 0) { info->num_incrs--; info->conversions[i].offset = -1; } } break; } /* Check if we're finished with all the targets */ if (info->num_incrs == 0) { current_incrs = g_list_remove_link (current_incrs, tmp_list); g_list_free (tmp_list); /* Let the timeout free it */ } return TRUE;}/************************************************************* * gtk_selection_incr_timeout: * Timeout callback for the sending portion of the INCR * protocol * arguments: * info: Information about this incr * results: *************************************************************/static gintgtk_selection_incr_timeout (GtkIncrInfo *info){ GList *tmp_list; gboolean retval; GDK_THREADS_ENTER (); /* Determine if retrieval has finished by checking if it still in list of pending retrievals */ tmp_list = current_incrs; while (tmp_list) { if (info == (GtkIncrInfo *)tmp_list->data) break; tmp_list = tmp_list->next; } /* If retrieval is finished */ if (!tmp_list || info->idle_time >= 5) { if (tmp_list && info->idle_time >= 5) { current_incrs = g_list_remove_link (current_incrs, tmp_list); g_list_free (tmp_list); } g_free (info->conversions); /* FIXME: we should check if requestor window is still in use, and if not, remove it? */ g_free (info); retval = FALSE; /* remove timeout */ } else { info->idle_time++; retval = TRUE; /* timeout will happen again */ } GDK_THREADS_LEAVE (); return retval;}/************************************************************* * gtk_selection_notify: * Handler for "selection_notify_event" signals on windows * where a retrieval is currently in process. The selection * owner has responded to our conversion request. * arguments: * widget: Widget getting signal * event: Selection event structure * info: Information about this retrieval * results: * was event handled? *************************************************************/gintgtk_selection_notify (GtkWidget *widget, GdkEventSelection *event){ GList *tmp_list; GtkRetrievalInfo *info = NULL; guchar *buffer = NULL; gint length; GdkAtom type; gint format; #ifdef DEBUG_SELECTION g_message ("Initial receipt of selection %ld, target %ld (property = %ld)", event->selection, event->target, event->property);#endif tmp_list = current_retrievals; while (tmp_list) { info = (GtkRetrievalInfo *)tmp_list->data; if (info->widget == widget && info->selection == event->selection) break; tmp_list = tmp_list->next; } if (!tmp_list) /* no retrieval in progress */ return FALSE; if (event->property != GDK_NONE) length = gdk_selection_property_get (widget->window, &buffer, &type, &format); if (event->property == GDK_NONE || buffer == NULL) { current_retrievals = g_list_remove_link (current_retrievals, tmp_list); g_list_free (tmp_list); /* structure will be freed in timeout */ gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, event->time); return TRUE; } if (type == gtk_selection_atoms[INCR]) { /* The remainder of the selection will come through PropertyNotify events */ info->notify_time = event->time; info->idle_time = 0; info->offset = 0; /* Mark as OK to proceed */ gdk_window_set_events (widget->window, gdk_window_get_events (widget->window) | GDK_PROPERTY_CHANGE_MASK); } else { /* We don't delete the info structure - that will happen in timeout */ current_retrievals = g_list_remove_link (current_retrievals, tmp_list); g_list_free (tmp_list); info->offset = length; gtk_selection_retrieval_report (info, type, format, buffer, length, event->time); } gdk_property_delete (widget->window, event->property); g_free (buffer); return TRUE;}/************************************************************* * gtk_selection_property_notify: * Handler for "property_notify_event" signals on windows * where a retrieval is currently in process. The selection * owner has added more data. * arguments: * widget: Widget getting signal * event: Property event structure * info: Information about this retrieval * results: * was event handled? *************************************************************/gintgtk_selection_property_notify (GtkWidget *widget, GdkEventProperty *event){ GList *tmp_list; GtkRetrievalInfo *info = NULL; guchar *new_buffer; int length; GdkAtom type; gint format; g_return_val_if_fail (widget != NULL, FALSE); g_return_val_if_fail (event != NULL, FALSE); if ((event->state != GDK_PROPERTY_NEW_VALUE) || /* property was deleted */ (event->atom != gdk_selection_property)) /* not the right property */ return FALSE; #ifdef DEBUG_SELECTION g_message ("PropertyNewValue, property %ld", event->atom);#endif tmp_list = current_retrievals; while (tmp_list) { info = (GtkRetrievalInfo *)tmp_list->data; if (info->widget == widget) break; tmp_list = tmp_list->next; } if (!tmp_list) /* No retrieval in progress */ return FALSE; if (info->offset < 0) /* We haven't got the SelectionNotify for this retrieval yet */ return FALSE; info->idle_time = 0; length = gdk_selection_property_get (widget->window, &new_buffer, &type, &format); gdk_property_delete (widget->window, event->atom); /* We could do a lot better efficiency-wise by paying attention to what length was sent in the initial INCR transaction, instead of doing memory allocation at every step. But its only guaranteed to be a _lower bound_ (pretty useless!) */ if (length == 0 || type == GDK_NONE) /* final zero length portion */ { /* Info structure will be freed in timeout */ current_retrievals = g_list_remove_link (current_retrievals, tmp_list); g_list_free (tmp_list); gtk_selection_retrieval_report (info, type, format, (type == GDK_NONE) ? NULL : info->buffer, (type == GDK_NONE) ? -1 : info->offset, info->notify_time); } else /* append on newly arrived data */ { if (!info->buffer) {#ifdef DEBUG_SELECTION g_message ("Start - Adding %d bytes at offset 0", length);#endif info->buffer = new_buffer; info->offset = length; } else { #ifdef DEBUG_SELECTION g_message ("Appending %d bytes at offset %d", length,info->offset);#endif /* We copy length+1 bytes to preserve guaranteed null termination */ info->buffer = g_realloc (info->buffer, info->offset+length+1); memcpy (info->buffer + info->offset, new_buffer, length+1); info->offset += length; g_free (new_buffer); } } return TRUE;}/************************************************************* * gtk_selection_retrieval_timeout: * Timeout callback while receiving a selection. * arguments: * info: Information about this retrieval * results: *************************************************************/static gintgtk_selection_retrieval_timeout (GtkRetrievalInfo *info){ GList *tmp_list; gboolean retval; GDK_THREADS_ENTER (); /* Determine if retrieval has finished by checking if it still in list of pending retrievals */ tmp_list = current_retrievals; while (tmp_list) { if (info == (GtkRetrievalInfo *)tmp_list->data) break; tmp_list = tmp_list->next; } /* If retrieval is finished */ if (!tmp_list || info->idle_time >= 5) { if (tmp_list && info->idle_time >= 5) { current_retrievals = g_list_remove_link (current_retrievals, tmp_list); g_list_free (tmp_list); gtk_selection_retrieval_report (info, GDK_NONE, 0, NULL, -1, GDK_CURRENT_TIME); } g_free (info->buffer); g_free (info); retval = FALSE; /* remove timeout */ } else { info->idle_time++; retval = TRUE; /* timeout will happen again */ } GDK_THREADS_LEAVE (); return retval;}/************************************************************* * gtk_selection_retrieval_report: * Emits a "selection_received" signal. * arguments: * info: information about the retrieval that completed * buffer: buffer containing data (NULL => errror) * time: timestamp for data in buffer * results: *************************************************************/static voidgtk_selection_retrieval_report (GtkRetrievalInfo *info, GdkAtom type, gint format, guchar *buffer, gint length, guint32 time){ GtkSelectionData data; data.selection = info->selection; data.target = info->target; data.type = type; data.format = format; data.length = length; data.data = buffer; gtk_signal_emit_by_name (GTK_OBJECT(info->widget), "selection_received", &data, time);}/************************************************************* * gtk_selection_invoke_handler: * Finds and invokes handler for specified * widget/selection/target combination, calls * gtk_selection_default_handler if none exists. * * arguments: * widget: selection owner * data: selection data [INOUT] * time: time from requeset * * results: * Number of bytes written to buffer, -1 if error *************************************************************/static voidgtk_selection_invoke_handler (GtkWidget *widget, GtkSelectionData *data, guint time){ GtkTargetList *target_list; guint info; g_return_if_fail (widget != NULL); target_list = gtk_selection_target_list_get (widget, data->selection); if (target_list && gtk_target_list_find (target_list, data->target, &info)) { gtk_signal_emit_by_name (GTK_OBJECT (widget), "selection_get", data, info, time); } else gtk_selection_default_handler (widget, data);}/************************************************************* * gtk_selection_default_handler: * Handles some default targets that exist for any widget * If it can't fit results into buffer, returns -1. This * won't happen in any conceivable case, since it would * require 1000 selection targets! * * arguments: * widget: selection owner * data: selection data [INOUT] * *************************************************************/static voidgtk_selection_default_handler (GtkWidget *widget, GtkSelectionData *data){ if (data->target == gtk_selection_atoms[TIMESTAMP]) { /* Time which was used to obtain selection */ GList *tmp_list; GtkSelectionInfo *selection_info; tmp_list = current_selections; while (tmp_list) { selection_info = (GtkSelectionInfo *)tmp_list->data; if ((selection_info->widget == widget) && (selection_info->selection == data->selection)) { gtk_selection_data_set (data, GDK_SELECTION_TYPE_INTEGER, sizeof (guint32)*8, (guchar *)&selection_info->time, sizeof (guint32)); return; } tmp_list = tmp_list->next; } data->length = -1; } else if (data->target == gtk_selection_atoms[TARGETS]) { /* List of all targets supported for this widget/selection pair */ GdkAtom *p; guint count; GList *tmp_list; GtkTargetList *target_list; GtkTargetPair *pair; target_list = gtk_selection_target_list_get (widget, data->selection); count = g_list_length (target_list->list) + 3; data->type = GDK_SELECTION_TYPE_ATOM; data->format = 8*sizeof (GdkAtom); data->length = count * sizeof (GdkAtom); p = g_new (GdkAtom, count); data->data = (guchar *)p; *p++ = gtk_selection_atoms[TIMESTAMP]; *p++ = gtk_selection_atoms[TARGETS]; *p++ = gtk_selection_atoms[MULTIPLE]; tmp_list = target_list->list; while (tmp_list) { pair = (GtkTargetPair *)tmp_list->data; *p++ = pair->target; tmp_list = tmp_list->next; } } else { data->length = -1; }}GtkSelectioData*gtk_selection_data_copy (GtkSelectionData *data){ GtkSelectionData *new_data; g_return_val_if_fail (data != NULL, NULL); new_data = g_new (GtkSelectionData, 1); *new_data = *data; return new_data;}voidgtk_selection_data_free (GtkSelectionData *data){ g_return_if_fail (data != NULL); g_free (data);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -