Alternative to gnome_url_show() in xfce - c

I would like to know if xfce has a function which works similar to gnome's gnome_url_show().
If this isn't the case I would like to know what would be another convenient way of opening a url? For example in case you added a signal handler to a button which upon clicking it opens a website.
Does gtk have such a function? I know it does have something built in at least, because when you create a label with a url in it it can be clicked to open the url. I have looked through various documentation but did not find a solution yet.
gtk_show_uri() is not going to work on xfce because it requires gvfs and I'm not using gnome.

Thanks to the xfce4-weather-plugin source I found this as a practical solution:
gchar *str = g_strdup_printf("exo-open --launch WebBrowser %s", url);
g_spawn_command_line_async(str, NULL);
g_free(str);
Considering the plugin is part of the core xfce apps I will assume it's the appropriate way to do it. I also found out about exo_execute_preferred_application() however I didn't feel like including another library.
A variation on this theme can be found here: http://git.xfce.org/xfce/libxfce4ui/tree/libxfce4ui/xfce-dialogs.c#n66
Which may be preferable because it will fall back to gtk_show_uri() in case exo is not installed. Although it's possible gtk_show_uri() may not work due to lack of gvfs on xfce systems (user is using xfce after all, not gnome). The xfce panel uses this function to load a url.
static void
xfce_dialog_show_help_uri (GdkScreen *screen,
GtkWindow *parent,
GString *uri)
{
GError *error = NULL;
gchar *path;
gchar *cmd;
gboolean result;
g_return_if_fail (GDK_IS_SCREEN (screen));
g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
path = g_find_program_in_path ("exo-open");
if (G_LIKELY (path != NULL))
{
cmd = g_strdup_printf ("%s --launch WebBrowser '%s'", path, uri->str);
result = xfce_spawn_command_line_on_screen (screen, cmd, FALSE, TRUE, &error);
g_free (path);
g_free (cmd);
}
else
{
/* not very likely to happen, but it is possible exo is not installed */
result = gtk_show_uri (screen, uri->str, gtk_get_current_event_time (), &error);
}
if (!result)
{
xfce_dialog_show_error (parent, error,
_("Failed to open web browser for online documentation"));
g_error_free (error);
}
}

Related

GtkSourceView-CRITICAL **: Highlighting a single line took too much time, syntax highlighting will be disabled

I'm experiencing this issue related to GtkSourceView4 and I want to understand how to avoid it
(litos:4353): GtkSourceView-CRITICAL **: 12:57:09.105: Highlighting a single line took too much time, syntax highlighting will be disabled
It happens when I try to insert tags such as <h1>, <h2> but not with other tags like <p>, <code>, etc.
It seems a bug that has already been filed https://bugzilla.redhat.com/show_bug.cgi?id=1882163 without solution.
Since I'm using other programs using GtkSourceView4 and highlighting works correctly it could be due to an improper usage of the API in particular the function gtk_source_buffer_set_highlight_syntax.
I'm using Gtksourceview4 and GTK3.
This is part of the code interested in highlighting the text
void open_file(struct lit *litos, gboolean template)
{
gboolean read_file_status;
GError *error;
char* contents;
gint page = gtk_notebook_get_current_page(litos->notebook);
char *filename = litos->filename[page];
read_file_status = g_file_get_contents(filename, &contents, NULL, &error);
if (read_file_status == FALSE)
{
g_error("error opening file: %s\n",error && error->message ? error->message : "No Detail");
return;
}
GtkTextBuffer *current_buffer = get_current_buffer(litos);
gtk_text_buffer_set_text(GTK_TEXT_BUFFER(current_buffer), contents, -1);
highlight_buffer(litos);
if (template)
{
litos->filename[page] = NULL;
filename = "Unsaved";
}
gtk_notebook_set_tab_label_text(
litos->notebook,
gtk_notebook_get_nth_page(
litos->notebook,
page
),
filename
);
gtk_notebook_set_menu_label_text(
litos->notebook,
gtk_notebook_get_nth_page(
litos->notebook,
page
),
filename
);
}
void highlight_buffer(struct lit *litos) /* Apply different font styles depending on file extension .html .c, etc */
{
gint page = gtk_notebook_get_current_page(litos->notebook);
GtkSourceLanguageManager *lm = gtk_source_language_manager_get_default();
GtkSourceLanguage *lang = gtk_source_language_manager_guess_language(lm, litos->filename[page], NULL);
gtk_source_buffer_set_language (litos->buffer, lang);
if (lang != NULL)
gtk_source_buffer_set_highlight_syntax (litos->buffer, TRUE);
}
you can find the complete program here https://github.com/gioretikto/litos
It's a bug in GtkSouceview 4; I noticed the same critical alert in gedit and mousepad as well. After downgrading to version GtkSourceview3 the issue was fixed.

Dialog creation and destruction loop increases memory usage

I wrote a simple program module to ask a user for a profile name. To do that I create windoww with entry widget, and two buttons (Ok and Cancel) organized in a grid. When user enters a profile name that already exists it informs him of that fact by creating dialog with "ok" button, and after he presses it, it goes back to picking a profile name (the window was not hidden nor destroyed in the meantime). The problem is that when I create a profile, and then spam the ok button (by placing something heavy on enter key and going to make tea) on both profile name chooser and the dialog (making a simple loop with creation and destruction of a dialog) the memory usage of the program increases.
TL;DR
Simply creating and destroying gtk window (and dialog) seems to cause a memory leak. Leaving app in a loop made it increase it's memory usage by ~1900% (from 10mb to 200mb).
No, I didn't test for memory leaks using apps designed for it.
Yes, I've set G_SLICE=always-malloc.
Yes, there is another thread running in the background of the program (but I'm sure it doesn't cause any leaks)
I can post screens from Windows Performance Monitor if you want more info on what happens in the memory.
The question is - is it a memory leak caused by me, or is it GTK's fault (I heard it has a lazy policy of memory management, but after some time memory usage drops from 200mb to 140mb and stays there)?
Here's the code:
// This callback racts to the ok and cancel buttons. If input was correcs
// or the user pressed cancel it destroys the window. Else it show error
// prompt. The showing error prompt seems to be the problem here.
void pickNameButtCB(GtkWidget *button, gpointer *call)
{
GtkWidget *window = gtk_widget_get_toplevel(button);
if( *((char*)call) == 'k')
{
GList *entryBase = gtk_container_get_children(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(window)))), *entry = entryBase;
for(size_t i=g_list_length(entry); i>0 && !GTK_IS_ENTRY(entry->data); --i)
entry = g_list_next(entry);
if(gtk_entry_get_text_length(GTK_ENTRY(entry->data)) > 0)
{
const char *temp = gtk_entry_get_text(GTK_ENTRY(entry->data));
char path[266];
strcpy(path, settingsDir);
strcat(path, temp);
strcat(path, ".prof");
if(settProfExists(path))
{
g_list_free(entryBase);
showError(GTK_WINDOW(window), GTK_MESSAGE_ERROR, "Profile with that name already exists!");
return;
}
// nothing here executes as well
}
else
{
/** doesn't execute when the memory leak happens */
}
g_list_free(entryBase);
}
gtk_widget_destroy(window);
gtk_main_quit();
}
void showError(GtkWindow *parent, GtkMessageType type, const char *str)
{
GtkWidget *window = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, str);
g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window);
gtk_dialog_run(GTK_DIALOG(window));
}
bool settProfExists(const char *path)
{
if(fileExists(path))
return true;
return false;
}
bool fileExists(const char *path)
{
struct stat info;
errno = 0;
if((stat(path, &info)) != 0)
if(errno == ENOENT)
return false;
return true;
}
Your code is too incomplete to find the root cause.
This line especially is doesn't make sense. We're missing the definition of entry and you're trying to do several operations on the same line (*entry = entryBase;).
GList *entryBase = gtk_container_get_children(GTK_CONTAINER(gtk_bin_get_child(GTK_BIN(window)))), *entry = entryBase;
The leak may however be in functions you call for which you don't provide the code (settProfExists, newProfile). So please provide a minimal compilable example that reproduces the problem.
As for the style, there are several errors: you're traversing a list the way you'd do with an array. See how is implemented GList and you'll see that this is silly (hint: look at entry->prev and entry->next):
for(size_t i=g_list_length(entry); i>0 && !GTK_IS_ENTRY(entry->data); --i)
entry = g_list_next(entry);
Then an architectural problem: don't try to inspect your UI to guess where are the widgets, just create a structure, and pass you call parameter and the GtkEntry you're interested in, in a structure with the gpointer data argument of the callback.
You should also not make paths by hand: you're using a fixed length array that may not be long enough. Use the portable g_build_path provided by the GLib (and free the path with g_free after use), that will handle for you Windows/Linux directories separators.
For your dialog, as you run gtk_run_dialog, you may just directly call gtk_destroy_widget afterwards instead of connecting a signal:
GtkWidget *window = gtk_message_dialog_new(parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, str);
gtk_dialog_run(GTK_DIALOG(window));
gtk_widget_destroy(window);

switching to a specific window

I'm writing a program using XLIB and gtk, I'm supposed to implement a function to switch a specific window(using any human identifyable reference, window name, process name or anything that is going to be static everytime that application is run)
I'm completely lost and I cannot find anything to guide me through the beginning of the application
thanks
You can do this with X libraries but it'll be a bit of a pain: you'll have to understand X IPC and properties. Fortunately there's an easier way, assuming you can use other libraries: use Libwnck. Here's a minimal example to list windows (adapted from the "Getting started" page):
WnckScreen *screen = wnck_screen_get_default ();
WnckWindow *active_window = wnck_screen_get_active_window (screen);
GList *l;
for (l = wnck_screen_get_windows (screen); l != NULL; l = window_l->next) {
WnckWindow *window = WNCK_WINDOW (window_l->data);
g_print ("%s%s\n", wnck_window_get_name (window),
window == active_window ? " (active)" : "");
}
Switching to a specific window should be just:
wnck_window_activate (window, 0);
The only gotcha is that wnck is designed to be used with a GLib mainloop. If you are not running one (as would be the case for a simple command line app), you'll need to use wnck_screen_force_update () to fetch the current data from X (see the "Getting started" example).

Open Windows Explorer Shell context menu

How do I enumerate the shell context menu item using Windows API? I need to do it in pure C.
It is a little unclear to me if you want to show a menu or just enumerate the items, this does the latter (Excluding submenus)
HRESULT GetContextMenuForFSItem(PCTSTR path,IContextMenu**ppCM)
{
PIDLIST_ABSOLUTE pidlAbs;
HRESULT hr = SHParseDisplayName(path,0,&pidlAbs,0,0);
if (!hr)
{
IShellFolder*pSF;
PCUITEMID_CHILD pidlLast;
hr = SHBindToParent(pidlAbs,&IID_IShellFolder,(void**)&pSF,&pidlLast);
if (!hr)
{
hr = pSF->lpVtbl->GetUIObjectOf(pSF,0,1,&pidlLast,&IID_IContextMenu,0,(void**)ppCM);
pSF->lpVtbl->Release(pSF);
}
ILFree(pidlAbs);
}
return hr;
}
int main()
{
CoInitialize(0);
WCHAR buf[MAX_PATH];
GetWindowsDirectory(buf,MAX_PATH); /* Arbitrary filesystem item */
IContextMenu*pCM;
HRESULT hr = GetContextMenuForFSItem(buf,&pCM);
if (!hr)
{
HMENU hMenu = CreatePopupMenu();
hr = pCM->lpVtbl->QueryContextMenu(pCM,hMenu,0,1,0x7fff,0);
if (hr > 0)
{
UINT c=GetMenuItemCount(hMenu), i=0;
for (; i<c; ++i)
{
GetMenuString(hMenu,i,buf,MAX_PATH,MF_BYPOSITION);
if (GetMenuState(hMenu,i,MF_BYPOSITION)&MF_SEPARATOR) lstrcpy(buf,_T("--separator--"));
printf("%.2u=%ws\n",i,buf);
/*
Call IContextMenu::GetCommandString to get the verb
or IContextMenu::InvokeCommand to execute
*/
}
}
pCM->lpVtbl->Release(pCM);
DestroyMenu(hMenu);
}
CoUninitialize();
return 0;
}
On my system this prints:
00=&Open
01=--separator--
02=S&hare with
03=Restore previous &versions
04=&Include in library
05=--separator--
06=Se&nd to
07=--separator--
08=Cu&t
09=&Copy
10=--separator--
11=Create &shortcut
12=&Delete
13=--separator--
14=P&roperties
Using COM in C is not fun, switch to C++ if you can...
You need to do exactly what Explorer does: for the item in question (file, folder, other shell namespace location) you identify the list of shell extensions. These are COM classes and they implement IContextMenu interface. For every shell extension applicable, you can provide your own menu and request that such extension (handler) populates the menu with its additional items (IContextMenu::QueryContextMenu).
Later on you are free to decide when, where and if you are going to pop this menu up. Should there a need in handle one of those additional handler's commands, you are responsible to fowrward the command to the handler via IContextMenu::InvokeCommand. If you for some reason prefer to automate certain command and invoke it without popping up the menu, you can do it as well.
Links you might be interested in:
How to access Windows shell context menu items?
Creating Shortcut Menu Handlers
Raymond Chen wrote an eleven part series explaining how to do this. It's really not straightforward.

CreateDesktop() with vista and UAC on (C, windows)

I asked this in CreateDesktop() with Vista UAC (C Windows)
I set a bounty but in trying to vote down the only answer the "accept" was pressed by mistake (i've been awake for more than 48 hs). so I am asking it again.
I'm using CreateDesktop() to create a temporary desktop where an application will run, perform a cleanup action (while remaining out of the way) and terminate. I'm closing that desktop once the application is gone. Everything is fine when using Windows XP and even Vista. The problem arises when you enable the (annoying) UAC.
Everything is OK when you create a desktop, but when you call CreateProcess() to open a program on that desktop it causes the opened application to crash with an exception on User32.dll.
I've been reading a lot about the different desktops and layers on Windows and the restrictions of memory. However, most of the programs I open (as test scenarios) are OK, but a few (like IE, Notepad, Calc and my own application) cause the crash.
Anyone has any idea why this happen on Vista with UAC, or more specifically for those specific programs? and how to fix this?
Anyone has a good solid example on how to create a desktop and open an application there without switching to it under Vista with UAC on?
Code is appreciated.
Thanks
The code used is
SECURITY_ATTRIBUTES sa;
HDESK dOld;
HDESK dNew;
BOOL switchdesk, switchdesk2, closedesk;
int AppPid;
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
//Get handle to current desktop
dOld = OpenDesktopA("default", 0, TRUE, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU);
if(!dOld)
{
printf("Failed to get current desktop handle !!\n\n");
return 0;
}
//Make a new desktop
dNew = CreateDesktopA("kaka", 0, 0, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, &sa);
if(!dNew)
{
printf("Failed to create new desktop !!\n\n");
return 0;
}
AppPid = PerformOpenApp(SomeAppPath);
if(AppPid == 0)
{
printf("failed to open app, err = %d\n", GetLastError());
}
else
{
printf("App pid = %d\n", AppPid);
}
closedesk = CloseDesktop(dNew);
if(!closedesk)
{
printf("Failed to close new desktop !!\n\n");
return 0;
}
return 0;
The correct solution is given as a short comment by ChristianWimmer above:
The desktop must have a security descriptor that allows access to lower integrity level like IE has. Otherwise the GUI cannot access the desktop. – ChristianWimmer Jul 22 '10 at 17:00
Since the answer is a little bit hidden and there's no source code example, let me state it clearly here:
If IE runs in protected mode then the browser tabs are created as low integrity processes. The low integrity tab process will fail to initialize if the desktop does not have a low integrity mandatory label.
As a consequence, the main IE process terminates, too. An interesting observation is that if you start IE providing a command line URL from the secure zone, then IE will succeed to start, because protected mode is disabled by default for the secure zone.
I checked the integrity level of the default desktop, and indeed I was able to verify that the default desktop has a low integrity level! So the easiest solution to the problem is to (1) create the new desktop, (2) get the mandatory label from the default desktop, and (3) copy it into the new desktop. For (2) and (3), you can use the following code
PACL pSacl;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
DWORD dwResult;
dwResult = GetSecurityInfo(hDefaultDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSacl, &pSecurityDescriptor);
if (dwResult == ERROR_SUCCESS) {
if (pSacl != NULL) {
dwResult = SetSecurityInfo(hNewDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);
if (dwResult != ERROR_SUCCESS)
_tprintf(_T("SetSecurityInfo(hNewDesktop) failed, error = %d"), dwResult);
}
LocalFree(pSecurityDescriptor);
} else {
_tprintf(_T("GetSecurityInfo(hDefaultDesktop) failed, error = %d"), dwResult);
}
#CristianWimmer: Thanks for providing the hint to the correct solution. This saved my a lot of time!!
You appear to have come across a bug in IE as it interacts with UAC. If protected mode is set to on you cannot run IE as an ordinary user in any desktop except the default one. In order to run IE in an alternate desktop you must be running as administrator or have protected mode set to off. This is true for Vista, W2K8 and Win7.
As to the other programs that you cannot run, unfortunately I can't confirm anything. I tried upwards of thirty different programs including notepad, calc, all the office apps, visual studio 2005, 2008 and 2010, MSDN help and a number of others and all worked as expected with the noted exception of IE. Is there something truly unusual about your app that might make it behave in an unexpected manner?
One note - if you attempt to run an application like this that needs elevation (such as regedit, etc.) it will fail in CreateProcess with the last error set to ERROR_ELEVATION_REQUIRED.
For your reference, in case I'm doing something different from you, the code I used is:
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
#endif
#include <stdio.h>
#include <tchar.h>
#include "windows.h"
HANDLE PerformOpenApp(TCHAR* appPath);
int _tmain(int argc, _TCHAR* argv[])
{
HDESK dNew;
BOOL closedesk;
HANDLE hApp;
//Make a new desktop
dNew = CreateDesktop(_T("kaka"), 0, 0, 0, DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS|
DESKTOP_READOBJECTS|
DESKTOP_ENUMERATE|
DESKTOP_CREATEWINDOW|
DESKTOP_CREATEMENU, NULL);
if(!dNew)
{
_tprintf(_T("Failed to create new desktop !!\n\n"));
return 0;
}
TCHAR path[MAX_PATH];
_putts(_T("Enter the path of a program to run in the new desktop:\n"));
_getts(path);
while(_tcslen(path) > 0)
{
hApp = PerformOpenApp(path);
if(hApp == 0)
{
_tprintf(_T("Failed to open app, err = %d\n"), GetLastError());
}
else
{
_tprintf(_T("App pid = %d\n"), GetProcessId(hApp));
_putts(_T("Press any key to close the app.\n"));
_gettchar();
TerminateProcess(hApp, 0);
CloseHandle(hApp);
}
_putts(_T("Enter the path of a program to run in the new desktop:\n"));
_getts(path);
}
closedesk = CloseDesktop(dNew);
if(!closedesk)
{
_tprintf(_T("Failed to close new desktop !!\n\n"));
return 0;
}
return 0;
}
HANDLE PerformOpenApp(TCHAR* appPath)
{
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
si.cb = sizeof(si);
si.lpDesktop = _T("kaka");
BOOL retVal = CreateProcess(NULL, appPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,
NULL, &si, &pi);
if (retVal)
{
CloseHandle(pi.hThread);
}
return pi.hProcess;
}

Resources